//
//  HJCryptoTool.m
//  KaiChat
//
//  Created by lx on 2023/12/2.
//

#import "HJCryptoTool.h"
#import <CommonCrypto/CommonCrypto.h>

@implementation HJCryptoTool


+ (NSString *)encryptString:(NSString *)string {
    NSInteger seed = [self getSeed];
    NSString *key = [self generateRandomStringWithLength:16 seed:seed];
    NSString *iv = [self generateRandomStringWithLength:16 seed:seed];
    NSData *encryptedData = [self encryptAES_CBCWithContent:string key:key iv:iv];
    NSString *base64String = [encryptedData base64EncodedStringWithOptions:0];
    return [self reversalWithBase64String:base64String newOrder:@[@3, @1, @0, @2]];;
}

+ (NSString *)decryptString:(NSString *)string iv:(NSString *)iv {
    NSInteger seed = [self getSeed];
    NSString *key = [self generateRandomStringWithLength:16 seed:seed];
    NSString *resultString = [self reversalWithBase64String:string newOrder:@[@2,@1, @3, @0]];
    NSData *decryptedData = [self decryptAES_CBCWithBase64String:resultString key:key iv:iv];
    return [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];;
}

+ (NSString *)encryptString:(NSString *)string iv:(NSString **)iv {
    NSInteger seed = [self getSeed];
    NSString *key = [self generateRandomStringWithLength:16 seed:seed];
    *iv = [self generateRandomStringWithLength:16]; // 使用指针参数传递 iv
    NSData *encryptedData = [self encryptAES_CBCWithContent:string key:key iv:*iv];
    NSString *base64String = [encryptedData base64EncodedStringWithOptions:0];
    return [self reversalWithBase64String:base64String newOrder:@[@3, @1, @0, @2]];;
}


+ (NSString *)reversalWithBase64String:(NSString *)base64String newOrder:(NSArray<NSNumber *> *)order {
    
    NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
    const uint8_t *bytes = [decodedData bytes];
    NSUInteger length = [decodedData length];
    
    NSUInteger chunkSize = length / 4;
    NSArray *chunks = @[
        [NSData dataWithBytes:bytes length:chunkSize],
        [NSData dataWithBytes:bytes + chunkSize length:chunkSize],
        [NSData dataWithBytes:bytes + 2 * chunkSize length:chunkSize],
        [NSData dataWithBytes:bytes + 3 * chunkSize length:length - 3 * chunkSize]
    ];
    
    NSMutableArray *reorderedChunks = [NSMutableArray arrayWithCapacity:[order count]];
    for (NSNumber *index in order) {
        [reorderedChunks addObject:chunks[[index intValue]]];
    }
    
    NSMutableData *mergedData = [NSMutableData data];
    for (NSData *chunk in reorderedChunks) {
        [mergedData appendData:chunk];
    }
    
    NSString *finalBase64String = [mergedData base64EncodedStringWithOptions:0];
    return finalBase64String;
}


+ (NSInteger)getSeed {
    NSInteger time = [NSString stringWithFormat:@"%.f", [NSDate date].timeIntervalSince1970].integerValue;
    NSInteger yu = time % 300;
    NSInteger min = time - yu;
    NSInteger max = min + 300;
    NSInteger seed = (min + max) / 2;
    return seed;
}


+ (NSString *)generateRandomStringWithLength:(int)length {
    NSString *charset = @"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
    for (NSUInteger i = 0; i < length; i++) {
        NSUInteger randomIndex = arc4random_uniform((uint32_t)charset.length);
        unichar randomChar = [charset characterAtIndex:randomIndex];
        [randomString appendFormat:@"%C", randomChar];
    }
    
    return randomString;
}

+ (NSString *)generateRandomStringWithLength:(int)length seed:(NSInteger)seed {
    
    NSString *charset = @"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
    NSMutableString *result = [NSMutableString stringWithCapacity:length];
    
    unsigned int a = 1664525, c = 1013904223;
    UInt64 m = 0x100000000;
    NSInteger x = seed;
    
    for (int i = 0; i < length; i++) {
        x = (a * x + c) % m;
        [result appendString:[charset substringWithRange:NSMakeRange(x % charset.length, 1)]];
    }
    
    return result;
}

+ (NSData *)encryptAES_CBCWithContent:(NSString *)content key:(NSString *)key iv:(NSString *)iv {
    
    NSData *inputData = [content dataUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];
    
    size_t bufferSize = [inputData length] + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t encryptedSize = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(
                                          kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          [keyData bytes],
                                          [keyData length],
                                          [ivData bytes],
                                          [inputData bytes],
                                          [inputData length],
                                          buffer,
                                          bufferSize,
                                          &encryptedSize
                                          );
    
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
    }
    
    free(buffer);
    return nil;
}

+ (NSData *)decryptAES_CBCWithBase64String:(NSString *)base64String key:(NSString *)key iv:(NSString *)iv {
    
    NSData *encryptedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];
    
    size_t bufferSize = [encryptedData length] + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t decryptedSize = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(
                                          kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          [keyData bytes],
                                          [keyData length],
                                          [ivData bytes],
                                          [encryptedData bytes],
                                          [encryptedData length],
                                          buffer,
                                          bufferSize,
                                          &decryptedSize
                                          );
    
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    }
    
    free(buffer);
    return nil;
}



@end
